/**
*  \file mcu.c
*
*  \brief Controller abstraction Layer
*
*  \author 
*
*   This Unit provide an interface to the application to use hardware features.
*
*
*/

/*===============================================[ private includes  ]================================================*/
#include <xmc4500/encoder_hw.h>
#include <xmc4500/i2c_hw.h>
#include <xmc4500/int.h>
#include <xmc4500/pwm_hw.h>
#include <xmc4500/switch_hw.h>
#include "../assertor/assertor.h"
#include "../sched/sched.h"
#include "../pal/pal_mem.h"
#include "../switch/switch.h"
#include "../adc/adc.h"
#include "../bis/bis.h"
#include "../specs/specs.h"
#include "../specs/specs_hw.h"
#include "../parameter/calibration.h"

#include "mcu.h"

/*===============================================[ private defines   ]================================================*/
#define MCU_GET_INPUT( pin )            ((BO) (( ((XMC_GPIO_PORT_t *const )( pin & 0xFFFFFF00))->IN) >> (pin&0xFF)) & 0x1U)
#define MCU_SET_OUTPUT( pin, value )    (((XMC_GPIO_PORT_t *) (pin & 0xFFFFFF00))->OMR = (value ? U32_CONST(0x0001) : U32_CONST(0x10000)) << (pin & 0xFF))
#define BootBISAddress                  0x0800FFE0
#define AppBISAddress                   0x080FFFE0



/*===============================================[ private datatypes ]================================================*/
struct mcu_private
{
    struct tasklet task_10ms;                                     /**< tasklet running on 10ms loop of RTS */
};

/*===============================================[ private variables ]================================================*/

static struct mcu_private mcu;

/*===============================================[ private functions ]================================================*/
static void mcu_10ms_service (struct tasklet *task);

/*===============================================[ inline functions  ]================================================*/

/*===============================================[ public functions  ]================================================*/

RC mcu_initialize( void )
{
    pal_memzero( &mcu, sizeof(mcu) );
    tasklet_assign( sched_get_slice_10ms(), &mcu.task_10ms,  mcu_10ms_service, NIL );
    return RC_SUCCESS;
}

F32 mcu_get_adc( enum mcu_adc  channel )
{
    switch (channel)
    {
        case mcu_adc_TempMotInv1:         return (F32)AD_TempMotInv1;
        case mcu_adc_TempMotInv2:         return (F32)AD_TempMotInv2;
        case mcu_adc_5VExtSns:            return (F32)AD_5VExtSns*specs_hw->ADC_Resol_5V;
        case mcu_adc_13_7VSupply:         return (F32)AD_13_7VSupply*specs_hw->ADC_Resol_13V;
        case mcu_adc_DcLink:              return (F32)AD_DcLink*specs_hw->ADC_Resol_UBat;
        case mcu_adc_Accelerator1:        return (F32)AD_Accelerator1*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_Accelerator2:        return (F32)AD_Accelerator2*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_SteerAngleA:         return (F32)AD_SteerAngleA*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_SteerAngleB:         return (F32)AD_SteerAngleB*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_Reserve1:            return (F32)AD_Reserve1*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_lift_Pot:            return (F32)AD_Reserve2*specs_hw->ADC_Resol_Relsts;
        case mcu_adc_CurrentCutOffIso:    return (F32)AD_CurrentCutOffIso*specs_hw->ADC_Resol_Curr;
        case mcu_adc_CurrentMainCont:     return (F32)AD_CurrentMainCont*specs_hw->ADC_Resol_Curr;
        case mcu_adc_KeySwitch:           return (F32)AD_KeySwitch*specs_hw->ADC_Resol_UBat*(1.0f+(F32)calibration->key_switch_cal/1000.0f);
        case mcu_adc_12VSupply:           return (F32)AD_12VSupply*specs_hw->ADC_Resol_13V;
        default: ASSERTOR_ILLEGAL_DEFAULT("invalid adc channel");
    }
    return 0;
}

void mcu_set_pwm(enum mcu_pwm channel, U16 value )
{
   switch (channel)
   {
      case mcu_pwm_contactor:
      {
         set_main_cnt_duty(value);
         break;
      }
      case mcu_pwm_iso_valve:
      {
         set_iso_valve_duty(value);
         break;
      }
      default:
      {
         ASSERTOR_ILLEGAL_DEFAULT("Unexpected PWM channel");
         break;
      }
   }
}

BO mcu_get_input(  enum mcu_input pin )
{
    switch (pin)
    {
        case EN_FORWARD_IN_D_CPU_V:             return Forward_In_Switch;
        case EN_BOOT_ANCHOR_CPU_M:              return Boot_Anchor_In_Switch;
        case EN_SEAT_SWITCH_NC_IN_D_CPU_V:      return Seat_Nc_In_Switch;
        case EN_NEUTRAL_POSITION_IN_D_CPU_V:    return Neutral_Position_In_Switch;
        case EN_REVERSE_IN_D_CPU_V:             return Reverse_In_Switch;
        case EN_LIFT_IN_D_CPU_V:                return Lift_In_Switch;
        case EN_TILT_IN_D_CPU_V:                return Tilt_In_Switch;
        case EN_MAST_AUX_1_IN_D_CPU_V:          return Mast_Aux1_In_Switch;
        case EN_MAST_AUX_2_IN_D_CPU_V:          return Mast_Aux2_In_Switch;
        case EN_SEAT_SWITCH_IN_D_CPU_V:         return Seat_In_Switch;
        case EN_RESERVE_1_IN_D_CPU_V:           return Reserve1_In_Switch;
        case EN_MAIN_CONTACTOR_ERROR:           return Main_Cont_Error_In_Switch;
        case EN_CUT_OFF_ISO_VALVE_ERROR:        return Cutoff_ISO_Valve_Error_In_Switch;
        case EN_BUZZER_ERROR:                   return Buzzer_Error_In_Switch;
        case EN_CPU_SYNC:                       return CPU_Sync_Switch;
        case EN_TLF_INT:                        return Tlf_int_Switch;
        case EN_PARK_BRAKE_IN_D_CPU_V:          return Park_Brake_In_Switch;
        case EN_TLF_SAFESTATE1:                 return Tlf_safeState1_Switch;
        case EN_FAN_ERROR:                      return Fan_Error_In_Switch; 

        default: ASSERTOR_ILLEGAL_DEFAULT("invalid pin channel");
    }
    return 0;

}

S32 mcu_get_motor_speed(void)
{
    return motor_speed;
}


void mcu_set_output( enum mcu_output pin , U8 value )
{
    MCU_SET_OUTPUT(pin,value);
}

U32 mcu_get_reset_reason(void)
{
    U32 reset = 0;
    return reset;
}

U32 mcu_high_resolution_counter(void)
{
    return u32OsTaskCnt;
}

U32 mcu_get_build_time_app(void)
{
   struct bis *app_bis = (struct bis *)AppBISAddress;
   return app_bis->build_time;
}

U32 mcu_get_build_time_bb(void)
{
   struct bis *boot_bis = (struct bis *)BootBISAddress;
   
   return boot_bis->build_time;
}

/*===============================================[ private functions ]================================================*/
static void mcu_10ms_service (struct tasklet *task)
{
    UNREFERENCED( task );
}

/***********************************************************************************************************************
*                             Copyright 2018 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/
